package com.zhuangfei.ohos_timetableview.views;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ScrollView;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

/**
 * ElasticScrollView
 * <p>
 * 弹性滚动布局，下拉时会反弹
 *
 * @since 2021-03-29
 */
public class ElasticScrollView extends ScrollView implements Component.TouchEventListener {
    private Component inner;
    private double yy;
    private Rect normal = new Rect();
    private boolean animationFinish = true;

    /**
     * ElasticScrollView
     *
     * @param context
     */
    public ElasticScrollView(Context context) {
        super(context);
    }

    /**
     * ElasticScrollView
     *
     * @param context
     * @param attrs
     */
    public ElasticScrollView(Context context, AttrSet attrs) {
        super(context, attrs);
    }

    /**
     * commOnTouchEvent
     *
     * @param ev
     */
    public void commOnTouchEvent(TouchEvent ev) {
        if (animationFinish) {
            int action = ev.getAction();
            MmiPoint point = ev.getPointerPosition(ev.getIndex());
            switch (action) {
                case TouchEvent.PRIMARY_POINT_DOWN:
                    yy = point.getY();
                    break;
                case TouchEvent.PRIMARY_POINT_UP:
                    yy = 0;
                    if (isNeedAnimation()) {
                        animation();
                    }
                    break;
                case TouchEvent.POINT_MOVE:
                    final double preY = yy == 0 ? point.getY() : yy;
                    double nowY = point.getY();
                    int deltaY = (int) (preY - nowY);

                    yy = nowY;
                    /**
                     * 当滚动到最上或者最下时就不会再滚动，这时移动布局
                     */
                    if (isNeedMove()) {
                        if (normal.isEmpty()) {
                            /**
                             * 保存正常的布局位置
                             */
                            normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom());
                        }
                        /**
                         * 移动布局
                         */
                        inner.setComponentPosition(inner.getLeft(), inner.getTop() - deltaY / 2, inner.getRight(), inner.getBottom() - deltaY / 2);
                    }
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 开启动画移动
     */
    public void animation() {
        AnimatorProperty ta = new AnimatorProperty(inner);
        ta.moveFromX(0).moveToX(0).moveFromY(0).moveToY(normal.top - inner.getTop()).setDelay(200);
        ta.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                inner.setComponentPosition(normal.left, normal.top, normal.right, normal.bottom);
                normal.set(0, 0, 0, 0);
                animationFinish = true;
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        ta.start();
    }

    /**
     * 是否需要开启动画
     *
     * @return 是否需要开启动画
     */
    public boolean isNeedAnimation() {
        return !normal.isEmpty();
    }

    /**
     * 是否需要移动布局
     *
      * @return 是否需要移动布局
     */
    public boolean isNeedMove() {
        int offset = inner.getEstimatedHeight() - getHeight();
        int scrollY = getScrollValue(0);
        if (scrollY == 0 || scrollY == offset) {
            return true;
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (inner != null) {
            commOnTouchEvent(touchEvent);
        }
        return false;
    }
}